package com.zmj.sy.mom.srv.aps.service;

import cn.hutool.core.date.DatePattern;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zmj.sy.mom.srv.aps.bean.entity.resource.*;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BaseIdReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.stationweekday.StationWeekdayGetResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.stationweekday.StationWeekdayPubReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.weekdayscheme.WeekdaySchemeAddRuleReqVo;
import com.zmj.sy.mom.srv.aps.mapper.*;
import com.zmj.sy.mom.srv.aps.utils.MkBeanUtils;
import com.zmj.sy.mom.srv.aps.utils.ProjectConstants;
import com.zmj.sy.mom.srv.aps.utils.SyExceptionUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@RequiredArgsConstructor
@Service
public class StationWeekdaySchemeService {

    private final StationWeekdaySchemeMapper stationWeekdaySchemeMapper;

    private final StationWeekdayRuleMapper stationWeekdayRuleMapper;

    private final StationWeekdayMapper stationWeekdayMapper;

    private final ShiftMapper shiftMapper;
    private final ShiftTypeMapper shiftTypeMapper;
    private final StationMapper stationMapper;
    private final WeekdayRuleMapper weekdayRuleMapper;

    @Transactional(rollbackFor = Exception.class)
    public Integer add(StationWeekdayPubReqVo reqVo) {

        stationWeekdaySchemeMapper.delete(Wrappers.<StationWeekdayScheme>lambdaQuery().eq(StationWeekdayScheme::getStationId, reqVo.getStationId()));
        stationWeekdayRuleMapper.delete(Wrappers.<StationWeekdayRule>lambdaQuery().eq(StationWeekdayRule::getStationId, reqVo.getStationId()));

        // 简化模式必须校验星期规则，必须有周一到周日
        List<Integer> collect1 = reqVo.getRuleList().stream().filter(e -> e.getType() == 4).map(e -> Integer.valueOf(e.getValue())).sorted().collect(Collectors.toList());
        if (collect1.size() != 7) {
            throw SyExceptionUtils.e("简化模式必须有周一到周日");
        }
        if (collect1.get(0) != 1) {
            throw SyExceptionUtils.e("必须从星期一开始");
        }

        StationWeekdayScheme weekdayScheme = MkBeanUtils.copyProperties(reqVo, StationWeekdayScheme.class);
        weekdayScheme.setType(2);
        weekdayScheme.setStationId(reqVo.getStationId());
        stationWeekdaySchemeMapper.insert(weekdayScheme);

        List<StationWeekdayRule> collect = reqVo.getRuleList()
                .stream()
                .map(e -> MkBeanUtils.copyProperties(e, StationWeekdayRule.class))
                .collect(Collectors.toList());
        for (StationWeekdayRule weekdayRule : collect) {
            weekdayRule.setStationWeekdaySchemeId(weekdayScheme.getId());
            weekdayRule.setStationId(reqVo.getStationId());
            stationWeekdayRuleMapper.insert(weekdayRule);
        }
        return weekdayScheme.getId();
    }

    @Transactional(rollbackFor = Exception.class)
    public void pub(Integer id) {

        StationWeekdayScheme scheme = stationWeekdaySchemeMapper.selectById(id);
        List<Shift> shifts = shiftMapper.selectList(Wrappers.<Shift>lambdaQuery().eq(Shift::getShiftTypeId, scheme.getShiftTypeId()));
        List<StationWeekdayRule> ruleList = stationWeekdayRuleMapper.selectList(Wrappers.<StationWeekdayRule>lambdaQuery().eq(StationWeekdayRule::getStationWeekdaySchemeId, scheme.getId()));
        LocalDate startDate = scheme.getStartDate();
        LocalDate endDate = scheme.getEndDate();

        // 先删除这个日期上的所有日历
        stationWeekdayMapper.delete(Wrappers.<StationWeekday>lambdaQuery().between(StationWeekday::getShiftDay, startDate, endDate));

        // 日历和班次打散
        List<StationWeekday> allWeekday = Stream
                .iterate(startDate, s -> s.plusDays(1))
                .limit(startDate.until(endDate, ChronoUnit.DAYS) + 1)
                .flatMap(e ->
                        shifts.stream()
                                .map(shift -> {
                                    StationWeekday newDay = new StationWeekday();
                                    MkBeanUtils.copyPropertiesIgnore(shift, newDay);
                                    newDay.setShiftDay(e);
                                    newDay.setShiftSeq(shift.getSeq());
                                    newDay.setShiftId(shift.getId());
                                    return newDay;
                                })
                )
                .collect(Collectors.toList());

        // 匹配规则，可以抽成策略模式，数据量大，为了效率不建议
        for (StationWeekday w : allWeekday) {
            for (StationWeekdayRule weekdayRule : ruleList) {
                w.setStationId(weekdayRule.getStationId());
                if (weekdayRule.getType() == 4) {
                    if (weekdayRule.getValue().equals(String.valueOf(w.getShiftDay().getDayOfWeek().getValue()))) {
                        w.setDateType(weekdayRule.getDateType());
                        w.setWorkState(weekdayRule.getStatus());
                        w.setStationWeekdayRuleId(weekdayRule.getId());
                    }
                } else if (weekdayRule.getType() == 3) {
                    if (LocalDate.parse(weekdayRule.getValue(), DatePattern.NORM_DATE_FORMATTER).equals(w.getShiftDay())) {
                        w.setDateType(weekdayRule.getDateType());
                        w.setWorkState(weekdayRule.getStatus());
                        w.setText(weekdayRule.getText());
                        w.setStationWeekdayRuleId(weekdayRule.getId());
                    }
                } else if (weekdayRule.getType() == 2) {
                    String value = weekdayRule.getValue();
                    String[] split = value.split(ProjectConstants.WEEKDAY_RULE_WEEKVALUE_SPLIT);
                    if (split[0].equals(w.getShiftDay().toString()) && split[1].equals(String.valueOf(w.getShiftId()))) {
                        w.setDateType(weekdayRule.getDateType());
                        w.setWorkState(weekdayRule.getStatus());
                        w.setText(weekdayRule.getText());
                        w.setStationWeekdayRuleId(weekdayRule.getId());
                    }
                }
            }
        }

        // 保存
        for (StationWeekday weekday : allWeekday) {
            stationWeekdayMapper.insert(weekday);
        }
    }

    public StationWeekdayGetResVo get(BaseIdReqVo reqVo) {
        StationWeekdayScheme scheme = stationWeekdaySchemeMapper.selectOne(Wrappers.<StationWeekdayScheme>lambdaQuery().eq(StationWeekdayScheme::getStationId, reqVo.getId()));

        if(scheme == null){
            return new StationWeekdayGetResVo();
        }

        StationWeekdayGetResVo resVo = MkBeanUtils.copyProperties(scheme, StationWeekdayGetResVo.class);

        List<StationWeekdayRule> ruleList = stationWeekdayRuleMapper.selectList(Wrappers.<StationWeekdayRule>lambdaQuery().eq(StationWeekdayRule::getStationId, reqVo.getId()));
        ruleList.sort(Comparator.comparingInt(StationWeekdayRule::getSeq));
        resVo.setRuleList(ruleList.stream().map(e -> MkBeanUtils.copyProperties(e, WeekdaySchemeAddRuleReqVo.class)).collect(Collectors.toList()));

        return resVo;

    }

    @Transactional(rollbackFor = Exception.class)
    public StationWeekdayGetResVo stationGet(BaseIdReqVo reqVo) {
        Station station = stationMapper.selectById(reqVo.getId());

        ShiftType shiftType = shiftTypeMapper.selectById(station.getShiftTypeId());
        StationWeekdayGetResVo stationWeekdayGetResVo = MkBeanUtils.copyProperties(shiftType, StationWeekdayGetResVo.class);

        List<WeekdayRule> list = weekdayRuleMapper.lambdaQuery().eq(WeekdayRule::getShiftTypeId, shiftType.getId()).list();

        List<WeekdaySchemeAddRuleReqVo> collect = list.stream()
                .map(e -> MkBeanUtils.copyProperties(e, WeekdaySchemeAddRuleReqVo.class))
                .collect(Collectors.toList());

        stationWeekdayGetResVo.setRuleList(collect);

        stationWeekdayGetResVo.setShiftTypeId(station.getShiftTypeId());
        stationWeekdayGetResVo.setStartDate(shiftType.getStartDate());

        return stationWeekdayGetResVo;
    }
}
